<?php
// $Id: qdbmysql.class.php 10 2011-03-19 03:59:28Z tomqin@gmail.com $

/**
 * QDbMysql 类
 *
 * 支持主从分离
 *
 * @author TomQin <easychen@gmail.com>
 * @copyright Copyright (c) 2009-2012 SupeFun.Com Inc.
 * @package Core
 *
 */

/**
 * QDbMysql Class
 *
 * <code>
 * <?php
 * $mysql = new QDbMysql();
 *
 * $sql = "SELECT * FROM `user` LIMIT 10";
 * $data = $mysql->getAll($sql);
 * $name = strip_tags($_REQUEST['name']);
 * $age = intval($_REQUEST['age']);
 * $sql = "INSERT  INTO `user` (`name` , `age` , `regtime`) VALUES ('"  . $mysql->escape($name) . "' , '" . intval($age) . "' , NOW()) ";
 * $mysql->query($sql);
 * if($mysql->errno() != 0)
 * {
 *     die("Error:" . $mysql->errmsg());
 * }
 *
 * $mysql->closeDb();
 * ?>
 * </code>
 *
 * @package sae
 * @author EasyChen
 *
 */
class QDbMysql
{
	private $default_config = array(
		'host'   => 'localhost',
		'port'   => '',
		'user'   => 'root',
		'passwd' => 'pwd',
		'dbname' => '',
		'charset'=> ''
	);

	private $config = array();
	private $replication = false;

    private $error;
    private $errno;
    private $last_sql;

	const DB_MASTER = 0;
	const DB_SLAVER = 1;

    /**
     * 构造函数
     *
     * @param array $config 数据库配置
     * @param bool $replication 是否支持主从分离，true:支持，false:不支持，默认为true
     * @return void
     */
    function __construct($master = array(), $slaver = null)
    {
        $this->setConfig($master, true);
        if($slaver)
        {
        	$this->setConfig($slaver, false);
        }

        $this->replication = empty($slaver) ? false : true;
    }

    /**
     * 设置当 Master 服务器
     *
     * @param array $config 连接配置
     * @return void
     */
    public function setConfig($config, $is_master = true)
    {
    	$server = $is_master ? self::DB_MASTER : self::DB_SLAVER;

    	$config = $config + $this->default_config;
        $this->config[$server] = array(
			'host'   => $config['host'],
			'port'   => empty($config['port']) ? 3306 : $config['port'],
			'user'   => $config['user'],
			'passwd' => $config['passwd'],
			'dbname' => $config['dbname'],
			'charset'=> $config['charset'],
		);
    }

    /**
     * 运行Sql语句，返回结果集
     *
     * @param string $sql
     * @return void
     */
    public function query($sql)
    {
        $this->last_sql = $sql;
        $dblink = $this->replication ? $this->db_read() : $this->db_write();

        if ($dblink === false) {
            return false;
        }
        $ret = mysql_query($sql, $dblink);
        $this->save_error($dblink);
        return $ret;
    }

	public function fetchArray($result)
	{
		if ($result) {
			return mysql_fetch_array($result, MYSQL_ASSOC);
		} else {
			return null;
		}
	}

	public function fetchRow($result)
	{
		if ($result) {
			return mysql_fetch_row($result);
		} else {
			return null;
		}
	}

    /**
     * 运行Sql,以多维数组方式返回结果集
     *
     * @param string $sql
     * @param string $index 若指定，则以该字段作为排序值
     * @return array 成功返回数组，失败时返回false
     */
    public function getAll($sql, $index = false)
    {
        $data = array();
        $result = $this->query($sql);

        if (is_bool($result)) {
            return $result;
        } else {
        	if($index) {
		        while($array = $this->fetchArray($result))
		        {
		            $data[$array[$index]] = $array;
		        }
        	} else {
		        while($array = $this->fetchArray($result))
		        {
		            $data[] = $array;
		        }
        	}
        }

        mysql_free_result($result);

        if(count($data) > 0)
            return $data;
        else
            return false;
    }

    /**
     * 运行Sql,以数组方式返回结果集第一条记录
     *
     * @param string $sql
     * @return array 成功返回数组，失败时返回false
     */
    public function getLine($sql)
    {
        return $this->fetchArray($this->query($sql));
    }

    /**
     * 运行Sql,返回结果集第一条记录的第一个字段值
     *
     * @param string $sql
     * @return mixxed 成功时返回一个值，失败时返回false
     */
    public function getFirst($sql)
    {
        $data = $this->fetchRow($this->query($sql));
        if($data){
        	return $data[0];
        }else{
        	return null;
        }
    }

    /**
     * 同mysql_last_id函数
     * PHP's mysql_last_id()在id为big int时,会出现溢出,用Sql查询替代掉
     *
     * @return int 成功返回last_id,失败时返回false
     */
    public function lastId()
    {
        $result = mysql_insert_id($this->db_write());
        return $result;
    }

    /**
     * 关闭数据库连接
     *
     * @return bool
     */
    public function closeDb()
    {
        if(isset($this->db_read))
            @mysql_close($this->db_read);

        if(isset($this->db_write))
            @mysql_close($this->db_write);

    }

    /**
     *  同mysql_real_escape_string
     *
     * @param string $str
     * @return string
     */
    public function escape($str)
    {
        if(isset($this->db_read)) {
            $db = $this->db_read;
        } elseif(isset($this->db_write)) {
            $db = $this->db_write;
        } else {
            $db = $this->db_read();
        }

        return mysql_real_escape_string($db, $str);
    }

    /**
     * 返回错误码
     *
     * @return int
     */
    public function errno()
    {
        return $this->errno;
    }

    /**
     * 返回错误信息
     *
     * @return string
     */
    public function error()
    {
        return $this->error;
    }

    /**
     * 返回错误信息,error的别名
     *
     * @return string
     */
    public function errmsg()
    {
        return $this->error();
    }

    /**
     * @ignore
     */
    private function connect($is_master = true)
    {
		$srv = $is_master ? self::DB_MASTER : self::DB_SLAVER;

        if ($this->config[$srv]['port'] == 0) {
            $this->error = 13048;
            $this->errno = 'Not Initialized';
            return false;
        }

        if(!$db = mysql_connect($this->config[$srv]['host'] .':'. $this->config[$srv]['port'], $this->config[$srv]['user'], $this->config[$srv]['passwd'], $this->config[$srv]['dbname']))
        {
            Q::debug('can\'t connect to mysql ' . $this->config[$srv]['host'] . ':' . $this->config[$srv]['port']);
            $this->error = mysql_connect_error();
            $this->errno = mysql_connect_errno();
            return false;
        }
		mysql_select_db($this->config[$srv]['dbname'], $db);
        mysql_set_charset($this->config[$srv]['charset'], $db);

        return $db;
    }

    /**
     * @ignore
     */
    private function db_read()
    {
        if(isset($this->db_read))
        {
            mysql_ping($this->db_read);
            return $this->db_read;
        }
        else
        {
            if(!$this->replication) return $this->db_write();
            else
            {
                $this->db_read = $this->connect(false);
                return $this->db_read;
            }
        }
    }

    /**
     * @ignore
     */
    private function db_write()
    {
        if(isset($this->db_write))
        {
            mysql_ping($this->db_write);
            return $this->db_write;
        }
        else
        {
            $this->db_write = $this->connect(true);
            return $this->db_write;
        }
    }

    /**
     * @ignore
     */
    private function save_error($dblink)
    {
        $this->error = mysql_error($dblink);
        $this->errno = mysql_errno($dblink);
    }

	/**
	 * 删除 DELETE 操作
	 *
	 * @param string  $table
	 * @param string  $condition    查询条件
	 * @param int     $limit        限制删除行数
	 * @return mix  执行结果
	 */
	function delete($table, $condition, $limit = 0) {
		$where = empty($condition) ? '1' : $condition;
		$sql = "DELETE FROM `$table` WHERE $where ".($limit ? "LIMIT $limit" : '');
		return $this->query($sql);
	}

	/**
	 * 插入 INSERT/REPLACE 操作
	 *
	 * @param string  $table
	 * @param array   $data         Key/Value 数组，对应列/值
	 * @param boolean $replace	    是否使用 REPLACE INTO 方式
	 * @return mix  执行结果
	 */
	public function insert($table, $data = array(), $replace = false) {
		$sql = $this->implodeFields($data);
		$cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';
		$sql = "$cmd `$table` SET $sql";
		return $this->query($sql);
	}

	/**
	 * 更新 UPDATE 操作
	 *
	 * @param string  $table
	 * @param array   $data         Key/Value 数组，对应列/值
	 * @param boolean $condition    查询条件
	 * @param boolean $lowPriority  是否使用 LOW_PRIORITY 更新方式
	 * @return mix  执行结果
	 */
	public function update($table, $data = array(), $condition = '', $lowPriority = false) {
		$sql = $this->implodeFields($data);
		$cmd = "UPDATE ".($lowPriority ? 'LOW_PRIORITY' : '');
		$where = empty($condition) ? '1' : $condition;
		$sql = "$cmd `$table` SET $sql WHERE $where";
		return $this->query($sql);
	}

	private function implodeFields($array, $glue = ',') {
		$sql = $comma = '';
		foreach ($array as $k => $v) {
			$sql .= $comma."`$k`= '" .$this->quote($v)."'";
			$comma = $glue;
		}
		return $sql;
	}

/*
	function insert_file($file,$readfiles=''){
		$readfiles || $readfiles=read_file($file);
		$detail=explode("\n",$readfiles);
		$count=count($detail);
		for($j=0;$j<$count;$j++){
			$ck=substr($detail[$j],0,4);
			if( ereg("#",$ck)||ereg("--",$ck) ){
				continue;
			}
			$array[]=$detail[$j];
		}
		$read=implode("\n",$array);
		$sql=str_replace("\r",'',$read);
		$detail=explode(";\n",$sql);
		$count=count($detail);
		for($i=0;$i<$count;$i++){
			$sql=str_replace("\r",'',$detail[$i]);
			$sql=str_replace("\n",'',$sql);
			$sql=trim($sql);
			if($sql){
				if(eregi("^CREATE TABLE",$sql)){
					if( mysql_get_server_info() > '4.1'){
						if(!eregi('DEFAULT CHARSET=',$sql)){
							$sql="$sql DEFAULT CHARSET=".($GLOBALS[dbcharset]?$GLOBALS[dbcharset]:'gbk');
						}
					}elseif(eregi('DEFAULT CHARSET=',$sql)){
						$sql=preg_replace("/DEFAULT CHARSET=([^ ]+)/is",'',$sql);
					}
				}
				$this->query($sql);
				$check++;
			}


		}
		return $check;
	}
*/
}